package eu.fritschi.parachatcapture;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

import jpcap.JpcapCaptor;
import jpcap.NetworkInterface;
import jpcap.NetworkInterfaceAddress;

import org.apache.log4j.Logger;


public class ParachatCapture {
	private static final Logger logger = Logger.getLogger(ParachatCapture.class);

	/**
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
		StdOutErrLog.tieSystemOutAndErrToLog();
		logger.info("Parachat Capture v 0.1");
		
		Settings settings = Settings.getInstance();
		settings.initialize();
		
		NetworkInterface[] devices = JpcapCaptor.getDeviceList();
		for (int i = 0; i < devices.length; i++) {
			printNicInformation(devices[i], i);
		}
		
		logger.info(settings.toString());
		
		int deviceIndex = settings.getNetworkCaptureDeviceId();  // set index of the interface that you want to open.
		
		// Try to open dump file
		String dumpFilePath = settings.getDumpFile();
		File dumpFile = null;
		if (dumpFilePath != null && !dumpFilePath.trim().equals("")) {
			dumpFile = new File(dumpFilePath);
			if (!dumpFile.canWrite() && !dumpFile.createNewFile()) {
				logger.error("Cannot write to dump file: " + dumpFilePath);
				dumpFile = null;
			}
		}
		
		BlockingQueue<ParachatMessage> messageQueue = new LinkedBlockingQueue<ParachatMessage>();
		final ParachatCapturePacketReceiver parachatCapturePacketReceiver = new ParachatCapturePacketReceiver(messageQueue, dumpFile);
		if (dumpFile != null) {
			// Register shutdown hook that will free the dumpFile on shutdown.
			Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
				@Override
				public void run() {
					parachatCapturePacketReceiver.freeResources();
				}
			}));
		}

		//Open an interface with openDevice(NetworkInterface intrface, int snaplen, boolean promics, int to_ms)
		JpcapCaptor captor=JpcapCaptor.openDevice(devices[deviceIndex], 65535, false, 20);
		captor.setFilter("src host " + settings.getParachatHost(), true);
		
		ParachatMessageProcessor parachatMessageProcessor = new ParachatMessageProcessor(messageQueue);
		parachatMessageProcessor.start();
		
		//call processPacket() to let Jpcap call PacketPrinter.receivePacket() for every packet capture.
		captor.loopPacket(-1, parachatCapturePacketReceiver);
		captor.close();
	}
	
//	private static void printHex(byte[] bytes, int offset, int width) {
//		for (int index = 0; index < width; index++) {
//			if (index + offset < bytes.length) {
//				System.out.printf("%02x ", bytes[index + offset]);
//			} else {
//				System.out.print("	");
//			}
//		}
//	}
//
//
//	private static void printAscii(byte[] bytes, int index, int width)
//		throws UnsupportedEncodingException {
//		if (index < bytes.length) {
//			width = Math.min(width, bytes.length - index);
//			System.out.println(
//				":"
//					+ new String(bytes, index, width, "UTF-8").replaceAll("\r\n", " ").replaceAll(
//						"\n",
//						" "));
//		} else {
//			System.out.println();
//		}
//	}

	private static void printNicInformation(NetworkInterface device2, int i) {
//		logger.info(" datalink: " + device.datalink_name + "("
//				+ device.datalink_description + ")");
//		StringBuffer macAddress = new StringBuffer();
//		for (byte b : device.mac_address)
//			macAddress.append(Integer.toHexString(b & 0xff)).append(":");
//		logger.info(" MAC address:" + macAddress);
//		for (NetworkInterfaceAddress a : device.addresses)
//			logger.info(" address:" + a.address + " " + a.subnet + " "
//					+ a.broadcast);
//		


		//for each network interface
		//print out its name and description
		String newLine = System.getProperty("line.separator");
		StringBuffer sb = new StringBuffer("Nic ID ").append(i).append(": ").append(device2.name).append("(").append(device2.description).append(")").append(newLine);

		//print out its datalink name and description
		sb.append(" datalink: ").append(device2.datalink_name).append("(").append(device2.datalink_description).append(")").append(newLine);

		//print out its MAC address
		sb.append(" MAC address: ");
		for (byte b : device2.mac_address)
			sb.append(Integer.toHexString(b&0xff) + ":");
		sb.deleteCharAt(sb.length() -1);
		sb.append(newLine);

		//print out its IP address, subnet mask and broadcast address
		for (NetworkInterfaceAddress a : device2.addresses)
			sb.append(" address:").append(a.address).append(" ").append(a.subnet).append(" ").append(a.broadcast);
		
		logger.info(sb.toString());
	}
}
